package com.heima.comment.service.impl;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.fastjson.JSON;
import com.heima.audit.baidu.BaiduTextScan;
import com.heima.comment.service.CommentRepayService;
import com.heima.common.constants.CommentConstants;
import com.heima.common.constants.UserConstants;
import com.heima.feign.user.client.UserFeignClient;
import com.heima.model.comment.dtos.CommentRepayDto;
import com.heima.model.comment.dtos.CommentRepayLikeDto;
import com.heima.model.comment.dtos.CommentRepayListDto;
import com.heima.model.comment.pojos.ApComment;
import com.heima.model.comment.pojos.ApCommentLike;
import com.heima.model.comment.vos.ApCommentVo;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.pojos.ApUser;
import com.heima.utils.threadUtil.AppThreadLocalUtil;
import org.bson.types.ObjectId;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class CommentRepayServiceImpl implements CommentRepayService {


    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private BaiduTextScan baiduTextScan;



    /**
     * 根据评论id去查询所有的评论回复
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult load(CommentRepayListDto dto) {
        //1.非空判断
        if (dto.getCommentId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //2.设置默认参数
        if (dto.getSize() == 0) {
            dto.setSize(10);
        }
        //3.页码大小最大值
        dto.setSize(Math.min(dto.getSize(), 50));
        //4.根据文章id查评论，并排序分页
        Query query = Query.query(Criteria.
                        where("targetId").is(dto.getCommentId())
                        .and("createdTime").lt(dto.getMinDate()))
                .with(Sort.by(Sort.Direction.DESC, "createdTime"))
                .limit(dto.getSize());
        List<ApComment> apCommentList = mongoTemplate.find(query, ApComment.class);
        //5.非空判断评论
        if (apCommentList == null && apCommentList.size()<0) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //6.判断是游客，则直接返回
        ApUser apUser = AppThreadLocalUtil.getUser();
        if (apUser.getId() == 0) {
            return ResponseResult.okResult(apCommentList);
        }
        //7.是用户，则判断是否有点赞
        String COMMENT_REPAY_LIKE_Key = CommentConstants.COMMENT_REPAY_LIKE_ + apUser.getId() + "";
        Set<String> members = redisTemplate.opsForSet().members(COMMENT_REPAY_LIKE_Key);
        //7.1否，直接返回
        if (members == null) {
            return ResponseResult.okResult(apCommentList);
        }
        //7.2是，查询redis是否包含文章id
        List<ApCommentVo> apCommentVoList = apCommentList.stream().map(comment -> {
            ApCommentVo apCommentVo = new ApCommentVo();
            BeanUtils.copyProperties(comment, apCommentVo);
            if (members.contains(comment.getTargetId())) {
                //7.2.1是，赋值vo
                apCommentVo.setOperation((short) 0);
            }
            return apCommentVo;
        }).collect(Collectors.toList());
        //返回vo
        return ResponseResult.okResult(apCommentVoList);
    }

    /**
     * 点赞评论方法
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult like(CommentRepayLikeDto dto) {
        //1.检查参数
        if (dto.getCommentRepayId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //2.判断是否登录
        ApUser apUser = AppThreadLocalUtil.getUser();
        if (apUser == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        //3. 判断如果是游客身份则不允许发表评论
        if (apUser.getId() == 0) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN, "请登录之后再来评论！！");
        }
        //4.非空文章
        ApComment comment = mongoTemplate.findById(dto.getCommentRepayId(), ApComment.class);
        if (comment == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //5.定义点赞key
        String comment_REPAY_likes_key = CommentConstants.COMMENT_REPAY_LIKE_ + apUser.getId() + "";
        //6.从redis查询
        Boolean comment_likesFlag = redisTemplate.opsForSet().isMember(comment_REPAY_likes_key, dto.getCommentRepayId());
        //6.1有，并且是点赞评论，直接返回
        if (comment_likesFlag && dto.getOperation() == 0) {
            return ResponseResult.okResult(AppHttpCodeEnum.COMMENT_LIKES_END_SUCCESS);
        }
        //6.2有，并且是取消点赞评论，
        if (comment_likesFlag && dto.getOperation() == 1) {
            //6.2.1删除redis点赞数据，
            redisTemplate.opsForSet().remove(comment_REPAY_likes_key, dto.getCommentRepayId());
            //6.2.2删除MongoDB点赞数据
            Query query = Query.query(Criteria.where("userID").is(apUser.getId()).and("targetId").is(dto.getCommentRepayId()));
            mongoTemplate.remove(query, ApCommentLike.class);
            //6.2.3修改mongoDB评论点赞数-1
            Query query1 = Query.query(Criteria.where("id").is(comment.getId()).and("likes").gt(0));
            Update update = new Update().inc("likes", -1);
            mongoTemplate.updateFirst(query1, update, ApComment.class);

        }
        //6.3否，并且是点赞评论，
        if (!comment_likesFlag && dto.getOperation() == 0) {
            //6.3.1新增redis
            redisTemplate.opsForSet().add(comment_REPAY_likes_key, dto.getCommentRepayId());
            //6.3.2新增MongoDB点赞数据
            ApCommentLike apCommentLike = new ApCommentLike();
            apCommentLike.setId(ObjectId.get().toHexString());
            apCommentLike.setUserId(apUser.getId());
            apCommentLike.setTargetId(dto.getCommentRepayId());
            apCommentLike.setCreatedTime(new Date());
            mongoTemplate.insert(apCommentLike);

            //6.3.3修改mongoDB评论点赞数+1
            Query query = Query.query(Criteria.where("id").is(comment.getId()));
            Update update = new Update().inc("likes", 1);
            mongoTemplate.updateFirst(query, update, ApComment.class);

        }
        //7.返回数据
        comment = mongoTemplate.findById(dto.getCommentRepayId(), ApComment.class);

        //8.封装map
        HashMap<String, Object> map = new HashMap<>();
        map.put("likes", comment.getLikes());
        return ResponseResult.okResult(map);
    }

    /**
     * 保存评论列表
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult saveCommentRepay(CommentRepayDto dto) {
        //1.检查参数
        if (dto.getCommentId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        if (dto.getContent() != null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //评论内容不能超过140字
        if (dto.getContent().length() > 140) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE, "评论内容不能超过140字");
        }
        //2.判断是否登录
        ApUser apUser = AppThreadLocalUtil.getUser();
        if (apUser == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        //2.5 判断如果是游客身份则不允许发表评论
        if (apUser.getId() == 0) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN, "请登录之后再来评论！！");
        }

        //3.查询用户信息------先从redis中查询，如果不存在再从用户微服务中去查询
        String apuserStr = redisTemplate.opsForValue().get(UserConstants.LOGIN_USER_ + apUser.getId());
        if (StringUtils.isBlank(apuserStr)) {//如果为空，则表示第一次
            //则远程从用户服务中调取
            ResponseResult<ApUser> result = userFeignClient.findUserById(apUser.getId().longValue());
            if (result.getCode() == 200 && result.getData() != null) {
                apUser = result.getData();

                //存入到redis中,并设置两个小时过期时间
                redisTemplate.opsForValue().set(UserConstants.LOGIN_USER_ + apUser.getId(), JSON.toJSONString(apUser), 2, TimeUnit.HOURS);
            }
        } else {//表示不是第一次，则直接从redis中取出
            apUser = JSON.parseObject(apuserStr, ApUser.class);
        }

        //4.对评论信息进行安全过滤
        Boolean flag = scanText(dto.getContent());
        if (!flag) {
            return ResponseResult.errorResult(AppHttpCodeEnum.COMMENT_BLOCK);
        }

        //5.保存数据到mongo中
        ApComment apComment = new ApComment();
        apComment.setId(ObjectId.get().toHexString());
        apComment.setUserId(apUser.getId());
        apComment.setNickName(apUser.getName());
        apComment.setContent(dto.getContent());
        apComment.setTargetId(String.valueOf(dto.getCommentId()));
        apComment.setCreatedTime(new Date());
        apComment.setUpdatedTime(new Date());
        apComment.setImage(apUser.getImage());
        apComment.setLikes(0);
        apComment.setReply(0);

        mongoTemplate.insert(apComment);
        Query query = Query.query(Criteria.where("id").is(dto.getCommentId()));
        UpdateDefinition updateDefinition = new Update().inc("reply", 1);

        mongoTemplate.updateFirst(query,updateDefinition,ApComment.class);

        return ResponseResult.okResult("评论成功");
    }

    /**
     * 对评论信息进行安全审核
     *
     * @param content
     * @return
     */
    private Boolean scanText(String content) {

        Boolean flag = true;

        //1.调用百度云审核的接口
        Integer status = baiduTextScan.textScan(content);

        //2.1判断状态，
        //为2，不合规，
        if (status == 2) {
            flag = false;
        }//为3，疑似合规
        else if (status == 3) {
            flag = false;
        }//为4，失败
        else if (status == 4) {
            flag = false;
        }
        return false;
    }



}
